<template>
	<div class="yudada">
		<!-- 地图容器 -->
		<div id="map"></div>
	</div>
</template>

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { onMounted } from 'vue';
import * as d3 from 'd3';
import { MeshBasicMaterial } from 'three';
import GUI from 'lil-gui';

// 贴图变量，后续加载中国地图图片
let quanGuoTexture = null; // 顶面贴图
let bottomTexture = null; // 底面贴图
let midTexture = null; // 中间层贴图

// 平行光全局变量
let directionalLight = null;
// 环境光全局变量
let ambientLight = null;

onMounted(() => {
	// 创建Three.js场景
	const scene = new THREE.Scene();

	// 添加环境光和多方向平行光
	ambientLight = new THREE.AmbientLight('#0062ff', 1.312); // 参数1：光的颜色，参数2：光的强度
	scene.add(ambientLight); // 将环境光添加到场景中

	// 添加第一个平行光（Directional Light）：模拟平行光源（如太阳），影响整个场景，会产生阴影。
	directionalLight = new THREE.DirectionalLight('#528EE4', 0.18); // 参数1：光的颜色，参数2：光的强度
	directionalLight.position.set(-3.6, 6.69, -2.12); // 设置光源的位置 (x, y, z)，这里是 (0, 10, 5) 代表光源在场景中偏上方的位置

	// 克隆第一个平行光并调整位置，创建多个方向的平行光。
	const directionalLight2 = directionalLight.clone(); // 克隆平行光对象
	directionalLight2.position.set(-3.6, 6.69, -2.12); // 设置第二个光源的位置，(0, 10, -5)，代表从场景的另一侧照射

	const directionalLight3 = directionalLight.clone(); // 克隆平行光对象
	directionalLight3.position.set(2.12, 6.69, 0); // 设置第三个光源的位置，(5, 10, 0)，从场景右侧照射

	const directionalLight4 = directionalLight.clone(); // 克隆平行光对象
	directionalLight4.position.set(-2.12, 6.69, 0); // 设置第四个光源的位置，(-5, 10, 0)，从场景左侧照射

	// 将所有平行光添加到场景中
	scene.add(directionalLight, directionalLight2, directionalLight3, directionalLight4);

	// 关键：在 directionalLight 创建和添加后立即调用 initGui
	// initGui();

	// 创建相机
	const camera = new THREE.PerspectiveCamera(
		75,
		window.innerWidth / window.innerHeight,
		0.1,
		1000
	);
	camera.position.y = 12;
	camera.position.z = 5;

	// 创建标签渲染器（用于省份名称等2D标签）
	const labelRenderer = new CSS2DRenderer();
	labelRenderer.domElement.style.position = 'absolute';
	labelRenderer.domElement.style.top = '0px';
	labelRenderer.domElement.style.pointerEvents = 'none';
	labelRenderer.setSize(window.innerWidth, window.innerHeight);
	document.getElementById('map').appendChild(labelRenderer.domElement);

	// 创建WebGL渲染器
	const renderer = new THREE.WebGLRenderer({ alpha: true });
	renderer.setSize(window.innerWidth, window.innerHeight);
	document.getElementById('map').appendChild(renderer.domElement);

	// 轨道控制器，支持鼠标缩放旋转
	const controls = new OrbitControls(camera, renderer.domElement);
	controls.update();

	// 开启阻尼
	controls.enableDamping = true;

	// 左右旋转范围
	controls.minAzimuthAngle = 0;
	controls.maxAzimuthAngle = 0;
	// 上下旋转范围
	controls.minPolarAngle = 0; //默认值0
	controls.maxPolarAngle = Math.PI / 2.3; //默认值Math.PI

	// controls.screenSpacePanning = false;
	// controls.zoomToCursor = false;
	// 动画循环
	const animate = () => {
		requestAnimationFrame(animate);
		controls.update();
		// 例如每帧加0.01
		materialAnimation(0.008, 'quanGuo');
		renderer.render(scene, camera);
		labelRenderer.render(scene, camera);
	};
	animate();

	// 窗口自适应
	window.addEventListener('resize', () => {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		renderer.setSize(window.innerWidth, window.innerHeight);
		labelRenderer.setSize(window.innerWidth, window.innerHeight);
	});

	// 加载三层贴图
	const textureLoader = new THREE.TextureLoader();
	quanGuoTexture = textureLoader.load('/hunan.png'); // 顶面
	bottomTexture = textureLoader.load('/hunan_bottom.png'); // 底面
	midTexture = textureLoader.load('/hunan_mid.png'); // 中间层

	// 加载GeoJSON数据
	const url = '/湖南省.json';
	fetch(url)
		.then((res) => res.json())
		.then((data) => {
			// data.features.pop(); // 去除南海诸岛

			// 1. 计算全中国的包围盒（所有省份的最大最小x/y）
			let minX = Infinity,
				minY = Infinity,
				maxX = -Infinity,
				maxY = -Infinity;
			const offsetXY = d3.geoMercator();
			const center = data.features[0].properties.centroid;
			offsetXY.center(center).translate([0, 0]);
			data.features.forEach((feature) => {
				const { coordinates, type } = feature.geometry;
				const allRings = type === 'MultiPolygon' ? coordinates.flat(1) : coordinates;
				allRings.forEach((ring) => {
					ring.forEach(([x, y]) => {
						const [px, py] = offsetXY([x, y]);
						minX = Math.min(minX, px);
						minY = Math.min(minY, -py);
						maxX = Math.max(maxX, px);
						maxY = Math.max(maxY, -py);
					});
				});
			});

			// 构建地图
			const map = createMap(data, minX, minY, maxX, maxY, offsetXY);
			scene.add(map);

			// 记录上一次选中的市区 unit 及其原 mesh/depth/位置
			let lastSelectedUnit = null;
			let lastOriginalMesh = null;
			let lastOriginalDepth = null;
			let lastOriginalPos = null;
			// 鼠标点击高亮
			// window.addEventListener('pointerdown', (event) => {
			// 	const mouse = new THREE.Vector2();
			// 	mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
			// 	mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
			// 	const raycaster = new THREE.Raycaster();
			// 	raycaster.setFromCamera(mouse, camera);
			// 	const intersects = raycaster
			// 		.intersectObjects(map.children, true)
			// 		.filter((item) => item.object.type === 'Mesh');
			// 	if (intersects.length > 0) {
			// 		// 找到所属的市区 unit（Object3D）
			// 		let unit = intersects[0].object.parent;
			// 		while (unit && !(unit instanceof THREE.Object3D && unit.name)) {
			// 			unit = unit.parent;
			// 		}
			// 		if (unit && unit !== lastSelectedUnit) {
			// 			// 恢复上一个市区
			// 			if (lastSelectedUnit && lastOriginalMesh) {
			// 				lastSelectedUnit.remove(lastSelectedUnit._mesh);
			// 				lastSelectedUnit.add(lastOriginalMesh);
			// 				lastSelectedUnit._mesh = lastOriginalMesh;
			// 				lastSelectedUnit._depth = lastOriginalDepth;
			// 				lastSelectedUnit.position.copy(lastOriginalPos);
			// 			}
			// 			// 记录当前unit的原始mesh、depth、位置
			// 			lastOriginalMesh = unit._mesh;
			// 			lastOriginalDepth = unit._depth;
			// 			lastOriginalPos = unit.position.clone();
			// 			// 替换当前市区 mesh 为高厚度
			// 			const newMesh = createMesh(
			// 				unit._geo,
			// 				0.8,
			// 				minX,
			// 				minY,
			// 				maxX,
			// 				maxY,
			// 				offsetXY
			// 			); // 0.8为凸起厚度
			// 			unit.remove(unit._mesh);
			// 			unit.add(newMesh);
			// 			unit._mesh = newMesh;
			// 			unit._depth = 0.8;
			// 			// 平移到地图中心（x=0, z=0）
			// 			unit.position.x = 0;
			// 			unit.position.z = 0;
			// 			lastSelectedUnit = unit;
			// 		}
			// 	} else {
			// 		// 点击空白处，恢复上一个市区
			// 		if (lastSelectedUnit && lastOriginalMesh) {
			// 			lastSelectedUnit.remove(lastSelectedUnit._mesh);
			// 			lastSelectedUnit.add(lastOriginalMesh);
			// 			lastSelectedUnit._mesh = lastOriginalMesh;
			// 			lastSelectedUnit._depth = lastOriginalDepth;
			// 			lastSelectedUnit.position.copy(lastOriginalPos);
			// 			lastSelectedUnit = null;
			// 			lastOriginalMesh = null;
			// 			lastOriginalDepth = null;
			// 			lastOriginalPos = null;
			// 		}
			// 	}
			// 	// 设置透明度
			// 	function isAplha(intersect, opacity) {
			// 		intersect.children.forEach((item) => {
			// 			if (item.type === 'Mesh') {
			// 				item.material.opacity = opacity;
			// 			}
			// 		});
			// 	}
			// });
		});

	// 初始化 lil-gui 调色面板
	// initGui(); // This line is moved to the top of the onMounted block
});

//侧边材质
const quanGuoUniform = {
	time: { value: 0 },
	start: { value: 10 },
	height: { value: 9 },
	maxTime: { value: 2 },
	speed: { value: 15 },
	color: { value: new THREE.Color('#116CD8') }
};

const quanGuoFragmentStr = `
    vec3 outgoingLight = reflectedLight.indirectDiffuse;
    vec3 gradient = mix(vec3(1.0,1.0,1.0),vec3(0,0,0),vPosition.z / 4.5);
    outgoingLight = outgoingLight*gradient;
    float y = uStart - uTime * uSpeed;
    float h = uHeight / 1.0;
    if(vPosition.z > y && vPosition.z < y + h * 1.0) {
        float per = 0.0;
        if(vPosition.z < y + h){
            per = ((vPosition.z - y) / h);
            outgoingLight = mix(uColor,outgoingLight,per);
        }else{
            outgoingLight = vec3(1,0,0);
        }
    }
    diffuseColor = vec4( outgoingLight, 0.8 );
`;

// 动画材质
const quanGuoSideMaterial = new MeshBasicMaterial({
	color: '#0459CE',
	transparent: true
});
quanGuoSideMaterial.onBeforeCompile = (shader) => {
	shader.uniforms = {
		...shader.uniforms,
		uTime: quanGuoUniform.time,
		uHeight: quanGuoUniform.height,
		uColor: quanGuoUniform.color,
		uStart: quanGuoUniform.start,
		uSpeed: quanGuoUniform.speed
	};
	shader.vertexShader = shader.vertexShader.replace(
		'void main() {',
		`
              varying vec3 vPosition;
              void main() {
                vPosition = position;
            `
	);
	shader.fragmentShader = shader.fragmentShader.replace(
		'void main() {',
		`
              varying vec3 vPosition;
              uniform float uTime;
              uniform vec3 uColor;
              uniform float uSpeed;
              uniform float uStart;
              uniform float uHeight;
              void main() {
            `
	);
	shader.fragmentShader = shader.fragmentShader.replace(
		'vec3 outgoingLight = reflectedLight.indirectDiffuse;',
		quanGuoFragmentStr
	);
};

// lil-gui 调色面板集成
function initGui() {
	const gui = new GUI();
	// 这里假设主材质和侧材质分别为 quanGuoSideMaterial 和 MeshStandardMaterial
	// 你可以根据实际情况调整变量名
	const guiParams = {
		topColor: '#69b08b',
		sideColor: '#123024',
		scale: 1
	};
	// 顶面材质（假设所有省份用同一个材质）
	let topFaceMaterial = null;
	// 侧面材质
	let sideMaterial = null;
	// 贴图对象
	let textureMap = quanGuoTexture;
	// 侧面材质对象
	sideMaterial = quanGuoSideMaterial;
	// 自动获取一个顶面材质对象（取第一个 MeshStandardMaterial）
	// 由于每个省份 mesh 都有独立材质，这里只取第一个做演示
	// 如需全部同步，可遍历 scene 或 map.children
	setTimeout(() => {
		const mapDiv = document.getElementById('map');
		if (mapDiv && mapDiv.children.length > 0) {
			// 尝试获取第一个 mesh 的材质
			const threeScene = mapDiv.__vue_app__?.config?.globalProperties?.$threeScene;
			// 这里无法直接拿到 scene，需在 createMesh 里暴露材质引用
		}
	}, 1000);
	// 直接用全局材质变量
	// 这里假设 quanGuoSideMaterial 是侧面材质
	// MeshStandardMaterial 需在 createMesh 里暴露
	// 这里用全局变量保存第一个顶面材质
	// 你可以在 createMesh 里加 window.topFaceMaterial = material[0];
	// 这里演示用法：
	// 顶面颜色
	gui.addColor(guiParams, 'topColor').onChange((val) => {
		// 遍历所有 mesh，修改其顶面材质颜色
		// 这里假设所有 mesh 的 material[0] 是 MeshStandardMaterial
		// 你可以在 createMap 里遍历 map.children 设置
		if (window._allTopMaterials) {
			window._allTopMaterials.forEach((mat) => {
				mat.color = new THREE.Color(val);
			});
		}
	});
	// 侧面颜色
	gui.addColor(guiParams, 'sideColor').onChange((val) => {
		if (sideMaterial) {
			sideMaterial.color = new THREE.Color(val);
		}
	});
	// 贴图缩放
	gui.add(guiParams, 'scale', 0, 1).onChange((val) => {
		if (textureMap) {
			textureMap.repeat.set(val, val);
			textureMap.needsUpdate = true;
		}
	});

	// 平行光参数
	if (directionalLight) {
		const lightParams = {
			color: directionalLight.color.getStyle(),
			intensity: directionalLight.intensity,
			x: directionalLight.position.x,
			y: directionalLight.position.y,
			z: directionalLight.position.z
		};
		gui.addColor(lightParams, 'color')
			.name('平行光颜色')
			.onChange((val) => {
				directionalLight.color.setStyle(val);
			});
		gui.add(lightParams, 'intensity', 0, 2)
			.name('平行光强度')
			.onChange((val) => {
				directionalLight.intensity = val;
			});
		gui.add(lightParams, 'x', -20, 20)
			.name('平行光X')
			.onChange((val) => {
				directionalLight.position.x = val;
			});
		gui.add(lightParams, 'y', 0, 20)
			.name('平行光Y')
			.onChange((val) => {
				directionalLight.position.y = val;
			});
		gui.add(lightParams, 'z', -20, 20)
			.name('平行光Z')
			.onChange((val) => {
				directionalLight.position.z = val;
			});
	}

	// 环境光参数
	if (ambientLight) {
		const ambientParams = {
			color: ambientLight.color.getStyle(),
			intensity: ambientLight.intensity
		};
		gui.addColor(ambientParams, 'color')
			.name('环境光颜色')
			.onChange((val) => {
				ambientLight.color.setStyle(val);
			});
		gui.add(ambientParams, 'intensity', 0, 2)
			.name('环境光强度')
			.onChange((val) => {
				ambientLight.intensity = val;
			});
	}
}

// 构建地图，所有省份贴图UV都基于全局包围盒
const createMap = (data, minX, minY, maxX, maxY, offsetXY) => {
	const map = new THREE.Object3D();
	data.features.forEach((feature) => {
		const unit = new THREE.Object3D();
		const { centroid, center, name } = feature.properties;
		const { coordinates, type } = feature.geometry;
		const point = centroid || center || [0, 0];
		// const depth = Math.random() * 0.3 + 0.3; // 随机厚度
		const depth = 0.4; // 随机厚度
		const label = createLabel(name, point, depth, offsetXY);
		// const icon = createIcon(center, depth, offsetXY);
		coordinates.forEach((coordinate) => {
			if (type === 'MultiPolygon') coordinate.forEach((item) => fn(item));
			if (type === 'Polygon') fn(coordinate);
			function fn(coordinate) {
				unit.name = name;
				// 传入全局包围盒参数
				const mesh = createMesh(coordinate, depth, minX, minY, maxX, maxY, offsetXY);
				const line = createLine(coordinate, depth, offsetXY);
				unit.add(mesh, ...line);
				unit._mesh = mesh; // 保存mesh引用
				unit._geo = coordinate; // 保存geo数据
				unit._depth = depth; // 保存原始厚度
			}
		});
		// map.add(unit, label, icon);
		map.add(unit, label);
		setCenter(map);
	});
	return map;
};

// 动画驱动函数
function materialAnimation(time, type) {
	quanGuoUniform.time.value += time;
	if (quanGuoUniform.time.value >= quanGuoUniform.maxTime.value) {
		quanGuoUniform.time.value = 0.0;
	}
}

// 创建省份立体Mesh，三层贴图（顶/中/底）
const createMesh = (data, depth, minX, minY, maxX, maxY, offsetXY) => {
	const shape = new THREE.Shape();
	data.forEach((item, idx) => {
		const [x, y] = offsetXY(item);
		if (idx === 0) shape.moveTo(x, -y);
		else shape.lineTo(x, -y);
	});
	const extrudeSettings = { depth, bevelEnabled: false };
	const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);

	// 顶面和底面uv归一化
	const pos = geometry.attributes.position;
	const uv = geometry.attributes.uv;
	for (let i = 0; i < pos.count; i++) {
		if (Math.abs(pos.getZ(i) - depth) < 1e-6 || Math.abs(pos.getZ(i)) < 1e-6) {
			const x = pos.getX(i);
			const y = pos.getY(i);
			const u = (x - minX) / (maxX - minX);
			const v = (y - minY) / (maxY - minY);
			uv.setXY(i, u, v);
		}
	}

	// === 顶面材质 ===
	const materialSettings = {
		emissive: 0x000000,
		roughness: 0.45,
		metalness: 0.8,
		transparent: false, // 贴图无透明时可设为 false
		alphaTest: 0.01,
		side: THREE.DoubleSide,
		color: '#ffffff',
		map: quanGuoTexture
	};
	const sideMaterial = quanGuoSideMaterial;
	const mesh = new THREE.Mesh(geometry, [
		new THREE.MeshStandardMaterial(materialSettings),
		sideMaterial
	]);

	// === 底面 mesh ===
	const shapeGeometryBottom = new THREE.ShapeGeometry(shape);
	// 设置底面uv
	const uvBottom = shapeGeometryBottom.attributes.uv;
	const posBottom = shapeGeometryBottom.attributes.position;
	for (let i = 0; i < posBottom.count; i++) {
		const x = posBottom.getX(i);
		const y = posBottom.getY(i);
		const u = (x - minX) / (maxX - minX);
		const v = (y - minY) / (maxY - minY);
		uvBottom.setXY(i, u, v);
	}
	const bottomMaterial = new THREE.MeshBasicMaterial({
		map: bottomTexture,
		transparent: true,
		opacity: 1
	});
	const bottomMesh = new THREE.Mesh(shapeGeometryBottom, bottomMaterial);
	bottomMesh.position.z = 0;

	// === 中间层 mesh ===
	const shapeGeometryMid = new THREE.ShapeGeometry(shape);
	const uvMid = shapeGeometryMid.attributes.uv;
	const posMid = shapeGeometryMid.attributes.position;
	for (let i = 0; i < posMid.count; i++) {
		const x = posMid.getX(i);
		const y = posMid.getY(i);
		const u = (x - minX) / (maxX - minX);
		const v = (y - minY) / (maxY - minY);
		uvMid.setXY(i, u, v);
	}
	const midMaterial = new THREE.MeshBasicMaterial({
		map: midTexture,
		transparent: true,
		opacity: 1
	});
	const midMesh = new THREE.Mesh(shapeGeometryMid, midMaterial);
	midMesh.position.z = depth / 2;

	// === 返回 group ===
	const group = new THREE.Group();
	group.add(mesh, bottomMesh, midMesh);

	// 收集所有顶面材质，供 lil-gui 批量调色
	if (!window._allTopMaterials) window._allTopMaterials = [];
	window._allTopMaterials.push(mesh.material[0]);
	return group;
};

// 省份边界线，青色
const createLine = (data, depth, offsetXY) => {
	const points = [];
	data.forEach((item) => {
		const [x, y] = offsetXY(item);
		points.push(new THREE.Vector3(x, -y, 0));
	});
	const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
	// 边框色为青色
	const uplineMaterial = new THREE.LineBasicMaterial({ color: '#3ACDFF', linewidth: 10 });
	const downlineMaterial = new THREE.LineBasicMaterial({ color: '#3ACDFF', linewidth: 10 });
	const upLine = new THREE.Line(lineGeometry, uplineMaterial);
	const downLine = new THREE.Line(lineGeometry, downlineMaterial);
	downLine.position.z = -0.01;
	upLine.position.z = depth + 0.01;
	return [upLine, downLine];
};

// 省份名称标签
const createLabel = (name, point, depth, offsetXY) => {
	const div = document.createElement('div');
	div.style.color = '#B6E0FF';
	div.style.fontSize = '14px';
	div.style.fontWeight = '500';
	div.style.textShadow = '1px 1px 2px #2E377C';
	div.style.textStroke = '1px #2E377C';
	div.textContent = name;
	const label = new CSS2DObject(div);
	label.scale.set(0.01, 0.01, 0.01);
	const [x, y] = offsetXY(point);
	label.position.set(x, -y, depth);
	return label;
};

// 省份图标
const createIcon = (point, depth, offsetXY) => {
	const url = new URL('../assets/icon.png', import.meta.url).href;
	const map = new THREE.TextureLoader().load(url);
	const material = new THREE.SpriteMaterial({
		map: map,
		transparent: true
	});
	const sprite = new THREE.Sprite(material);
	const [x, y] = offsetXY(point);
	sprite.scale.set(0.3, 0.3, 0.3);
	sprite.position.set(x, -y, depth + 0.2);
	sprite.renderOrder = 1;
	return sprite;
};

// 设置地图居中
const setCenter = (map) => {
	map.rotation.x = -Math.PI / 2;
	const box = new THREE.Box3().setFromObject(map);
	const center = box.getCenter(new THREE.Vector3());
	const offset = [1, 1];
	map.position.x = map.position.x - center.x - offset[0];
	map.position.z = map.position.z - center.z - offset[1];
};
</script>

<style lang="scss">
.yudada {
	background: url('/bg1.png') no-repeat center center;
	background-size: cover;
	background-size: 100% 100%;
	position: relative;
	width: 100%;
	height: 100%;
	&::before {
		content: '';
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		// background: rgba(0, 0, 0, 0.6); /* 黑色半透明遮罩层 */
		z-index: 1; /* 确保遮罩层在背景之上 */
	}
}
#map {
	position: absolute;
	z-index: 99;
	/* 背景图片 */
	// background: url('/bg1.png') no-repeat center center;
	// background-size: cover;
	// background-size: 100% 100%;
	// position: relative;
}
</style>
